package com.stray.crawl.model.dao;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.stray.crawl.Constants.PlanCategory;
import com.stray.crawl.model.CrawlPlan;
import com.stray.crawl.model.PlanUrl;
import com.stray.crawl.utils.ModelUtils;

public class InMemoryPlanRepository extends PlanRepository {

	private List<CrawlPlan> plans;
	private List<CrawlPlan> genericPlans;
	private Map<PlanUrl, CrawlPlan> urlPlanMap;

	public InMemoryPlanRepository() {
		plans = HardCodePlans.getPlans();
		genericPlans = HardCodePlans.getGenericPlans();

		urlPlanMap = new HashMap<PlanUrl, CrawlPlan>();

		for (CrawlPlan plan : plans) {
			for (PlanUrl u : plan.getUrls()) {
				urlPlanMap.put(u, plan);
			}
		}
		for (CrawlPlan plan : genericPlans) {
			for (PlanUrl u : plan.getUrls()) {
				urlPlanMap.put(u, plan);
			}
		}
	}

	@Override
	protected List<CrawlPlan> getPlans() {
		return plans;
	}

	@Override
	protected List<CrawlPlan> getGenericPlans() {
		return genericPlans;
	}

	@Override
	protected Collection<CrawlPlan> getPlansByHost(String host) {
		Set<CrawlPlan> results = new HashSet<CrawlPlan>();

		for (CrawlPlan plan : plans) {
			List<PlanUrl> urls = plan.getUrls();
			for (PlanUrl url : urls) {
				String h = formatter.extractHost(url.getUrl());
				if (h.equals(host)) {
					results.add(plan);
					break;
				}
			}
		}

		return results;
	}

	@Override
	protected CrawlPlan getPlanByUrl(PlanUrl url) {
		return urlPlanMap.get(url);
	}

	public static class HardCodePlans {

		public static List<CrawlPlan> getPlans() {
			return new ArrayList<CrawlPlan>(Arrays.asList(
					getHkgForumThreadPlan(),
					getHkgForumContentPlan(),
					getDiscuzzForumThreadPlan(),
					getDiscuzzForumContentPlan(),
					getItpubForumThreadPlan(),
					getItpubForumContentPlan()
				));
		}

		public static List<CrawlPlan> getGenericPlans() {
			return new ArrayList<CrawlPlan>(Arrays.asList(
					getGenericImagePlan()
				));
		}

		public static CrawlPlan getDiscuzzForumThreadPlan() {
			CrawlPlan plan = new CrawlPlan();

			plan.setPlanGroup("uwants");
			plan.setPlanCategory(PlanCategory.FORUM_THREAD);

			plan.setEnableReferer(false);
			plan.setEnableCache(true);

			plan.setDocumentCharset("big5");
			plan.setExpressQuery("jsoup/select(tbody[id^=normalthread] tr)");

			PlanUrl url1 = ModelUtils.addUrl(plan, "[http]www.uwants.com/forumdisplay.php");
			ModelUtils.addParam(url1, "forumId", "fid", RegexPattern.number, 'R', false);
			ModelUtils.addParam(url1, "page", "page", RegexPattern.number, 'R', true);

			PlanUrl url2 = ModelUtils.addUrl(plan, "[http]www.discuss.com.hk/forumdisplay.php");
			ModelUtils.addParam(url2, "forumId", "fid", RegexPattern.number, 'R', false);
			ModelUtils.addParam(url2, "page", "page", RegexPattern.number, 'R', true);

			ModelUtils.addFields(plan, new String[] {
				"id",			"child(2)/select(span[id])/first/child(0)/attr(href)/followUrl/substr(tid=,&extra)",
				"category",		"child(2)/select(em)/text/trim([])",
				"date",			"child(3)/select(em)/text",
				"replyCount",	"child(4)/select(strong)/text",
				"viewCount",	"child(4)/select(em)/text",
				"topic",		"child(2)/select(span[id])/text",
				"username",		"child(3)/select(cite)/text"
			});
			
			plan.setActionQuery("filePersist");

			return ModelUtils.generateName(plan);
		}

		public static CrawlPlan getHkgForumThreadPlan() {
			CrawlPlan plan = new CrawlPlan();

			plan.setPlanGroup("hkg");
			plan.setPlanCategory(PlanCategory.FORUM_THREAD);

			plan.setEnableReferer(false);
			plan.setEnableCache(true);

			plan.setDocumentCharset("big5");
			plan.setExpressQuery("jsoup/select(tr[userid])");

			ModelUtils.addUrl(plan, "[http][domain:string].hkgolden.com/topics_[category:string].htm");

			PlanUrl url2 = ModelUtils.addUrl(plan, "[http][domain:string].hkgolden.com/topics.aspx");
			ModelUtils.addParam(url2, "forumId", "type", RegexPattern.string, 'R', false);
			ModelUtils.addParam(url2, "page", "page", RegexPattern.number, 'R', true);

			ModelUtils.addFields(plan, new String[] {
				"id", 			"child(1,0)/attr(href)/substr(>message=)",
				"follow", 		"child(1,0)/attr(href)",
				"date", 		"child(3)/text/date(dd\\M\\yyyy HH:mm)",
				"replyCount", 	"child(4)/text",
				"rating", 		"child(5)/text",
				"topic", 		"child(1,0)/text",
				"username", 	"attr(username)"
			});

			return ModelUtils.generateName(plan);
		}

		public static CrawlPlan getItpubForumThreadPlan() {
			CrawlPlan plan = new CrawlPlan();

			plan.setPlanGroup("itpub");
			plan.setPlanCategory(PlanCategory.FORUM_THREAD);

			plan.setEnableReferer(false);
			plan.setEnableCache(true);

			plan.setDocumentCharset("gbk");
			plan.setExpressQuery("jsoup/select(table.tab1108 tbody tr)/sublist(1,0)");

			ModelUtils.addUrl(plan, "[http]www.itpub.net/forum-[forumId:number]-[page:number].html");
			ModelUtils.addFields(plan, new String[] {
				"id",			"child(0,0,0)/attr(href)/substr(thread-,-1-1.html)",
				"follow",		"child(0,0,0)/attr(href)",
				"category",		"child(1)/select(em)/text",
				"date",			"child(2)/select(em)/text",
				"replyCount",	"child(3)/text",
				"viewCount",	"child(4)/text",
				"topic",		"child(1)/select(a.xst)/text",
				"username",		"child(2)/select(cite)/text",
			});

			return ModelUtils.generateName(plan);
		}

		public static CrawlPlan getHkgForumContentPlan() {
			CrawlPlan plan = new CrawlPlan();

			plan.setPlanGroup("hkg");
			plan.setPlanCategory(PlanCategory.FORUM_CONTENT);

			plan.setEnableReferer(true);
			plan.setEnableCache(true);

			plan.setDocumentCharset("big5");
			plan.setExpressQuery("jsoup/select(tr[userid])");

			ModelUtils.generateName(plan);
			PlanUrl url1 = ModelUtils.addUrl(plan, "[http][domain:string].hkgolden.com/view.aspx");
			ModelUtils.addParam(url1, "threadId", "message", RegexPattern.number, 'R', false);
			ModelUtils.addParam(url1, "forumId", "type", RegexPattern.string, 'R', true);
			ModelUtils.addParam(url1, "page", "page", RegexPattern.number, 'R', true);

			ModelUtils.addFields(plan, new String[] {
				"index", 		"attr(id)/substr(>Thread_No)",
				"date", 		"child(1,0,0,2)/select(span)/text",
				"username", 	"attr(username)",
				"content", 		"child(1,0,0,0,0)/toString",
			});

			return ModelUtils.generateName(plan);
		}

		public static CrawlPlan getItpubForumContentPlan() {
			CrawlPlan plan = new CrawlPlan();

			plan.setPlanGroup("itpub");
			plan.setPlanCategory(PlanCategory.FORUM_CONTENT);

			plan.setEnableReferer(true);
			plan.setEnableCache(true);

			plan.setDocumentCharset("gbk");
			plan.setExpressQuery("jsoup/select(div#postlist div table[id])");

			ModelUtils.addUrl(plan, "[http]www.itpub.net/thread-[threadId:number]-[page:number]-1.html");
			ModelUtils.addFields(plan, new String[] {
				"index", 		"child(0,0,1,0)/select(em)/first/text",
				"date", 		"child(0,0,1,0)/select(em[id])/text/substr",
				"username", 	"child(0,0,0,0)/text",
				"content", 		"child(0,0,1,1)/select(td[id])/html",
			});

			return ModelUtils.generateName(plan);
		}

		public static CrawlPlan getDiscuzzForumContentPlan() {
			CrawlPlan plan = new CrawlPlan();

			plan.setPlanGroup("uwants-hkdiscuss");
			plan.setPlanCategory(PlanCategory.FORUM_CONTENT);

			plan.setEnableReferer(false);
			plan.setEnableCache(true);

			plan.setDocumentCharset("big5");
			plan.setExpressQuery("jsoup/select(div.viewthread table)");

			PlanUrl url1 = ModelUtils.addUrl(plan, "[http][domain:string].uwants.com/viewthread.php");
			ModelUtils.addParam(url1, "threadId", "tid", RegexPattern.number, 'R', false);
			ModelUtils.addParam(url1, "page", "page", RegexPattern.number, 'R', true);
			ModelUtils.addParam(url1, "extra", "extra", RegexPattern.string, 'R', true);

			PlanUrl url2 = ModelUtils.addUrl(plan, "[http][domain:string].discuss.com.hk/viewthread.php");
			ModelUtils.addParam(url2, "threadId", "tid", RegexPattern.number, 'R', false);
			ModelUtils.addParam(url2, "page", "page", RegexPattern.number, 'R', true);
			ModelUtils.addParam(url2, "extra", "extra", RegexPattern.string, 'R', true);

			ModelUtils.addFields(plan, new String[] {
				"index", 	"child(0,0,1)/select(.postinfo strong)/text",
				"date", 	"child(0,0,1)/select(.postinfo)/first/text(own)",
				"username", "child(0,0,0)/select(cite)/text",
				"topic", 	"child(0,0,1)/select(h2)/text",
				"content", 	"child(0,0,1,2)/children/last/child(0)/text",
			});

			return ModelUtils.generateName(plan);
		}

		public static CrawlPlan getGenericImagePlan() {
			CrawlPlan plan = new CrawlPlan();

			plan.setPlanGroup("generic");
			plan.setPlanCategory(PlanCategory.BINARY);

			plan.setEnableReferer(true);
			plan.setEnableCache(false);

			ModelUtils.addUrl(plan, "^https?://([\\w\\d:%/;$()~_+-\\.]*)([\\w\\d:%/;$()~_+-\\.]+\\.(png|gif|jpe?g)$)", false);

			return ModelUtils.generateName(plan);
		}

	}

}